/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.wsinfra.wse.impl;

import java.util.Calendar;

import javax.xml.namespace.QName;

import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlDateTime;

import cgl.narada.wsinfra.exception.ProcessingException;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.eventing.DeliveryType;
import cgl.narada.wsinfra.schemas.eventing.FilterType;
import cgl.narada.wsinfra.schemas.eventing.GetStatusDocument;
import cgl.narada.wsinfra.schemas.eventing.GetStatusResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.NotifyToDocument;
import cgl.narada.wsinfra.schemas.eventing.RenewDocument;
import cgl.narada.wsinfra.schemas.eventing.RenewResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscriptionEndDocument;
import cgl.narada.wsinfra.util.XmlContentTransfer;
import cgl.narada.wsinfra.wsa.WsaEprCreator;
import cgl.narada.wsinfra.wsa.WsaProcessingFactory;
import cgl.narada.wsinfra.wse.WseElementCreation;
import cgl.narada.wsinfra.wse.WseQNames;
import cgl.narada.wsinfra.wse.matching.SubscriptionEntry;

/** This is a utility class which is responsible for the creation of elements
    that are used within WS-Eventing.

    @author Shrideep Pallickara
    $Date: 2005/07/29 22:41:30 $
    $Revision: 1.3 $
*/

public class WseElementCreationImpl implements WseElementCreation {
  private static final WseElementCreation instance = new WseElementCreationImpl();
  private WseQNames wseQNames;
  private XmlContentTransfer xmlContentTransfer;
  private WsaEprCreator wsaEprCreator;

  private String moduleName = "WseElementCreation: ";
  
  private WseElementCreationImpl() {
    wseQNames = WseQNames.getInstance();
    xmlContentTransfer = XmlContentTransfer.getInstance();
    wsaEprCreator = WsaProcessingFactory.getWsaEprCreator();
  }
  
  
  public static WseElementCreation getInstance() {
    return instance;
  }



  /** This method creates a subscribe request document based on the
      specified arguments. */
  public SubscribeDocument
  newSubscribeDocument(String deliveryMode, EndpointReferenceType endTo,
		       String filterDialect, String filterConstraint,
		       Calendar expiresAt, EndpointReferenceType notifyTo)
    throws ProcessingException {
    
    String errorReport = null;
    if (notifyTo == null) {
      errorReport = moduleName + "The [wse:NotifyTo] element CANNOT be NULL!";
      throw new ProcessingException(errorReport);
    }
    
    SubscribeDocument subscribeDocument =
      SubscribeDocument.Factory.newInstance();
    SubscribeDocument.Subscribe subscribe= subscribeDocument.addNewSubscribe();
    
    if (deliveryMode != null) {
      DeliveryType delivery = subscribe.addNewDelivery();
      delivery.setMode(deliveryMode);
    }
    
    if (endTo != null) {
      subscribe.setEndTo(endTo);
    }
    
    if (filterDialect != null && filterConstraint != null) {
      FilterType filter = subscribe.addNewFilter();
      
      if (filterDialect != null) {
	filter.setDialect(filterDialect);
      }
      
      if (filterConstraint != null) {
	XmlCursor filterCursor = filter.newCursor();
	filterCursor.setTextValue(filterConstraint);
	filterCursor.dispose();
      }
    }
    
    if (expiresAt != null) {
      XmlDateTime expiry = getXmlDateTime(expiresAt);
      subscribe.setExpires((Object)expiry);
    }
    
    if (notifyTo != null) {
      NotifyToDocument notifyToDocument=NotifyToDocument.Factory.newInstance();
      notifyToDocument.setNotifyTo(notifyTo);
      xmlContentTransfer.
	copyFromSourceToDestinationAsLastChild(notifyToDocument,
					       subscribe);
    }

    return subscribeDocument;
  }

  
  
  /** This method creates a subscribe request document based on the
      specified arguments. */
  public SubscribeDocument
  newSubscribeDocument(String filterDialect, String filterConstraint,
		       Calendar expiresAt,  EndpointReferenceType notifyTo)
    throws ProcessingException {
    
    String deliveryMode = null;
    EndpointReferenceType endTo = null;
    
    return newSubscribeDocument(deliveryMode, endTo, filterDialect,
				filterConstraint, expiresAt, notifyTo);
  }
  


  /** This method creates a renew request document based on the
      newly created subscription entry */
  public RenewDocument newRenewDocument(Calendar expiresAt) 
    throws ProcessingException {
    String errorReport = null;
    if (expiresAt == null) {
      errorReport = "The ExpiresAt element for [wse:Renew] can not be NULL";
      throw new ProcessingException(errorReport);
    }
    
    RenewDocument renewDocument = RenewDocument.Factory.newInstance();
    RenewDocument.Renew renew = renewDocument.addNewRenew();

    if (expiresAt != null) {
      XmlDateTime expiry = getXmlDateTime(expiresAt);
      renew.setExpires(expiry);
    }

    return renewDocument;
  }


  
  
  /** This method creates a getStatus request document based on the
      newly created subscription entry */
  public GetStatusDocument newGetStatusDocument() {
    GetStatusDocument getStatusDocument =
      GetStatusDocument.Factory.newInstance();
    GetStatusDocument.GetStatus getStatus=getStatusDocument.addNewGetStatus();

    return getStatusDocument;
  }
  
  

  /** This method creates a subscribe response document based on the
      newly created subscription entry */
  public SubscribeResponseDocument
  newSubscribeResponseDocument(SubscriptionEntry subscriptionEntry)
    throws ProcessingException {

    checkSubscriptionEntryForProblems(subscriptionEntry);

    SubscribeResponseDocument subscribeResponseDoc =
      SubscribeResponseDocument.Factory.newInstance();

    SubscribeResponseDocument.SubscribeResponse subscribeResponse
      = subscribeResponseDoc.addNewSubscribeResponse();


    XmlDateTime xmlDateTime = getExpiry(subscriptionEntry);
    subscribeResponse.setExpires(xmlDateTime);

    EndpointReferenceType subscriptionManager =
      subscriptionEntry.getSubscriptionManager();

    /** This is done so that the referenceType of the subscriptionManager is
	not messed up. Otherwise every addition is continously added */
    EndpointReferenceType subscriptionManagerCopy =
      (EndpointReferenceType)subscriptionManager.copy();

    String subscriptionId = subscriptionEntry.getIdentifier();
    QName identifierQName = wseQNames.getIdentifier();
    wsaEprCreator.addElementToReferenceParameters(subscriptionManagerCopy,
						  identifierQName,
						  subscriptionId);
    subscribeResponse.setSubscriptionManager(subscriptionManagerCopy);


    return subscribeResponseDoc;

  }


  /** This method creates a renew response document based on the
      newly created subscription entry */
  public RenewResponseDocument
  newRenewResponseDocument(SubscriptionEntry  subscriptionEntry)
    throws ProcessingException {
    
    checkSubscriptionEntryForProblems(subscriptionEntry);

    RenewResponseDocument renewResponseDoc =
      RenewResponseDocument.Factory.newInstance();

    RenewResponseDocument.RenewResponse renewResponse
      = renewResponseDoc.addNewRenewResponse();

    XmlDateTime xmlDateTime = getExpiry(subscriptionEntry);
    renewResponse.setExpires(xmlDateTime);

    return renewResponseDoc;

  }




  /** This method creates a getStatus response document based on the
      specified subscription entry */
  public GetStatusResponseDocument
  newGetStatusResponseDocument(SubscriptionEntry  subscriptionEntry)
    throws ProcessingException {
    checkSubscriptionEntryForProblems(subscriptionEntry);

    GetStatusResponseDocument getStatusResponseDoc =
      GetStatusResponseDocument.Factory.newInstance();

    GetStatusResponseDocument.GetStatusResponse getStatusResponse
      = getStatusResponseDoc.addNewGetStatusResponse();

    XmlDateTime xmlDateTime = getExpiry(subscriptionEntry);
    getStatusResponse.setExpires(xmlDateTime);

    return getStatusResponseDoc;
  }



  /** This method create a SubscriptionEnd document based on the specified 
      subscription entry */
  public SubscriptionEndDocument
  newSubscriptionEndDocument(SubscriptionEntry  subscriptionEntry, 
			     String status, String reason)
    throws ProcessingException {
    checkSubscriptionEntryForProblems(subscriptionEntry);
    
    String errorReport = null;
    if (status == null || reason == null) {
      errorReport = moduleName + "the status=" + status + ", OR the reason=" +
	reason + " CANNOT be NULL.";
      throw new ProcessingException(errorReport);
    }
    
    SubscriptionEndDocument subscriptionEndDocument =
      SubscriptionEndDocument.Factory.newInstance();

    SubscriptionEndDocument.SubscriptionEnd subscriptionEnd =
      subscriptionEndDocument.addNewSubscriptionEnd();
    
    EndpointReferenceType subscriptionManager = 
      subscriptionEntry.getSubscriptionManager();
    subscriptionEnd.setSubscriptionManager(subscriptionManager);
    subscriptionEnd.setStatus(status);
    subscriptionEnd.addNewReason().setStringValue(reason);

    return subscriptionEndDocument;
  }

  /** Get the XMLDateTime expiry associated with the subscription entry */
  private XmlDateTime getExpiry(SubscriptionEntry subscriptionEntry) {
    XmlDateTime xmlDateTime = XmlDateTime.Factory.newInstance();
    Calendar expiresAt = subscriptionEntry.getExpiresAt();
    if (expiresAt == null) {
      /* This will not happen */
      System.out.println(moduleName + "The expiresAt value is null.");
      return xmlDateTime;
    }
    xmlDateTime.setCalendarValue(expiresAt);

    return xmlDateTime;
  }


  /** Checks to see if the specified subscription entry has problems */
  private void
  checkSubscriptionEntryForProblems(SubscriptionEntry  subscriptionEntry) 
    throws ProcessingException {
    String errorReport = null;
    if (subscriptionEntry == null) {
      errorReport = moduleName + "The specified subscription Entry is NULL.";
      throw new ProcessingException(errorReport);
    }
    
    String id = subscriptionEntry.getIdentifier();
    if (id == null) {
      errorReport = moduleName + "The identifier within the specified " +
	"Subscription Entry is a NULL!";
      throw new ProcessingException(errorReport);
    }
  }


  /** Get the XMLDateTime expiry associated with the subscription entry */
  private XmlDateTime getXmlDateTime(Calendar expiresAt) {
    XmlDateTime xmlDateTime = XmlDateTime.Factory.newInstance();
    if (expiresAt == null) {
      /* This should not happen */
      System.out.println(moduleName + "The expiresAt value is null.");
      return xmlDateTime;
    }
    xmlDateTime.setCalendarValue(expiresAt);

    return xmlDateTime;
  }

}
